#pragma once
#ifndef MATHUTIL_H
#define MATHUTIL_H

struct D3DXAABB 
{	
	D3DXVECTOR3 Min;
	D3DXVECTOR3 Max;

	inline
		D3DXAABB()
	{
		Min = D3DXVECTOR3();
		Max = D3DXVECTOR3();
	};

	inline
		D3DXAABB( D3DXVECTOR3 min, D3DXVECTOR3 max )
	{
		Min = min;
		Max = max;
	};

	inline
		D3DXAABB& operator += (const D3DXAABB& rhs)
	{
		Min += rhs.Min;
		Max += rhs.Max;
		return *this;
	};

	inline
		D3DXAABB& operator -= (const D3DXAABB& rhs)
	{
		Min -= rhs.Min;
		Max -= rhs.Max;
		return *this;
	};

	inline
		D3DXAABB& operator += (const D3DXVECTOR3& rhs)
	{
		Min += rhs;
		Max += rhs;
		return *this;
	};

	inline
		D3DXAABB& operator -= (const D3DXVECTOR3& rhs)
	{
		Min -= rhs;
		Max -= rhs;
		return *this;
	};

	inline
		D3DXAABB operator + () const
	{
		return *this;
	};

	inline
		D3DXAABB operator - () const
	{
		return D3DXAABB(-Min, -Max);
	};

	inline
		D3DXAABB operator + ( const D3DXVECTOR3& rhs ) const
	{
		return D3DXAABB(Min + rhs, Max + rhs);
	};

	inline
		D3DXAABB operator - ( const D3DXVECTOR3& rhs ) const
	{
		return D3DXAABB(Min - rhs, Max - rhs);
	};
};

struct INTVECTOR3
{
	int x;
	int z;
	int y;

	inline
		INTVECTOR3()
	{
		x = 0;
		y = 0;
		z = 0;
	};


	inline
		INTVECTOR3(int _x, int _z, int _y)
	{
		x = _x;
		y = _y;
		z = _z;
	};


	inline
		INTVECTOR3(const D3DXVECTOR3& rhs)
	{
		x = static_cast<int>(floor(rhs.x + 0.5f)); 
		y = static_cast<int>(floor(rhs.y + 0.5f)); 
		z = static_cast<int>(floor(rhs.z + 0.5f)); 
	};

	inline
		INTVECTOR3& operator += (const INTVECTOR3& rhs)
	{
		x += rhs.x;
		y += rhs.y;
		z += rhs.z;
		return *this;
	};


	inline
		INTVECTOR3& operator -= (const INTVECTOR3& rhs)
	{
		x -= rhs.x;
		y -= rhs.y;
		z -= rhs.z;
		return *this;
	};

	inline
		INTVECTOR3 operator + () const
	{
		return *this;
	};

	inline
		INTVECTOR3 operator - () const
	{
		return INTVECTOR3(-x, -z, -y);
	};

	inline
		bool operator == (const INTVECTOR3& rhs) const
	{
		return ((x == rhs.x) && (z == rhs.z) && (y == rhs.y));
	};

	inline
		bool operator < (const  INTVECTOR3& rhs) const
	{
		if (y < rhs.y)  return true;
		if (y > rhs.y)  return false;

		if (z < rhs.z)  return true;
		if (z > rhs.z)  return false;

		return (x < rhs.x);
	};

	inline
		bool operator > (const  INTVECTOR3& rhs) const
	{
		if (y > rhs.y)  return true;
		if (y < rhs.y)  return false;

		if (z > rhs.z)  return true;
		if (z < rhs.z)  return false;

		return (x > rhs.x);
	};
};

struct INTVECTOR4
{
	int x;
	int z;
	int y;
	int w;

	inline
		INTVECTOR4::INTVECTOR4()
	{
		x = 0;
		y = 0;
		z = 0;
		w = 0;
	};

	inline
		INTVECTOR4::INTVECTOR4(int _x, int _z, int _y, int _w)
	{
		x = _x;
		y = _y;
		z = _z;
		w = _w;
	};

	inline
		INTVECTOR4(const D3DXVECTOR4 &rhs)
	{
		x = static_cast<int>(floor(rhs.x + 0.5f)); 
		y = static_cast<int>(floor(rhs.y + 0.5f)); 
		z = static_cast<int>(floor(rhs.z + 0.5f)); 
		w = static_cast<int>(floor(rhs.w + 0.5f)); 
	};

	inline
		bool operator == (const INTVECTOR4& rhs) const
	{
		return ((x == rhs.x) && (z == rhs.z) && (y == rhs.y) && (w == rhs.w));
	};

	inline
		bool operator < (const  INTVECTOR4& rhs) const
	{
		if (x < rhs.x)  return true;
		if (x > rhs.x)  return false;

		if (y < rhs.y)  return true;
		if (y > rhs.y)  return false;

		if (z < rhs.z)  return true;
		if (z > rhs.z)  return false;

		return (w < rhs.w);
	};

	inline
		bool operator > (const  INTVECTOR4& rhs) const
	{
		if (x > rhs.x)  return true;
		if (x < rhs.x)  return false;

		if (y > rhs.y)  return true;
		if (y < rhs.y)  return false;

		if (z > rhs.z)  return true;
		if (z < rhs.z)  return false;

		return (w > rhs.w);
	};
};


/**
 * Clamps a given value to be an element of [0..1].
 */
double clamp(double value);

double clamp(double value, double min, double max);

float clamp(float value, float min, float max);

int clamp(int value, int min, int max);

/**
 * Linear interpolation.
 */
double lerp(double x, double x1, double x2, double q00, double q01);

double lerp(double x1, double x2, double p);

float lerpf(float x1, float x2, float p);

/**
 * Trilinear interpolation.
 */
double triLerp(double x, double y, double z, double q000, double q001, double q010, double q011, double q100, double q101, double q110, double q111, double x1, double x2, double y1, double y2, double z1, double z2);

#endif